<?php

namespace model\repo;

class Model
{
    /** @var string */
    protected $table;

    protected $pk = "_id";

    /** @var \mysqli */
    protected $db;

    public function __construct(/* string */$host, /* string */$user, /* string */$passwd,
        /* string */$db, /*int */$port = 3306)
    {
        $this->db = mysqli_connect($host,$user, $passwd, $db, $port);
        if (!$this->db) {
            throw new \InvalidArgumentException(mysqli_connect_error(), mysqli_connect_errno());
        }
        // 默认不输出SQL
        if (!defined("SQL_LOG")) {
            define("SQL_LOG", false);
        }
    }

    public function __destruct() {
        mysqli_close($this->db);
    }

    private function outLog(/* string */$s) {
        echo $s.PHP_EOL;
    }

    protected function queryGetRow(/* string */$table, /* string */$where) /* : array */
    {
        $sql = "SELECT * FROM `".$table."` WHERE ".$where;
        if (SQL_LOG) {
            $this->outLog($sql);
        }
        /** @var  $result \mysqli_result */
        $result = $this->db->query($sql);
        $row = mysqli_fetch_array($result, MYSQLI_ASSOC);
        if (empty($row)) {
            return array();
        }
        return $row;
    }

    /**
     * @throws \ErrorException
     */
    protected function queryGetAll(/* string */ $table, /* string */ $where,
        /* string */                            $limit = "", /* string */ $order = "") {
        $sql = "SELECT * FROM `".$table."` WHERE ".$where;
        if (SQL_LOG) {
            $this->outLog($sql);
        }
        if (!empty($order)) {
            $sql = " ORDER BY `".$this->pk."` DESC";
        }
        if (!empty($limit)) {
            $sql .= " LIMIT ".$limit;
        }
        /** @var  $result \mysqli_result */
        $result = $this->db->query($sql);
        if (empty($result)) {
            $errMsg = sprintf("MySQL ERROR %d: %s", $this->db->errno, mysqli_error($this->db));
            throw new \ErrorException($errMsg, $this->db->errno);
        }
        $rows = mysqli_fetch_all($result, MYSQLI_ASSOC);
        if (is_array($rows) && empty($rows)) {
            return array();
        }
        return $rows;
    }

    public function getTotal(/* string */$table, /* string */$where) {
        $sql = "SELECT count(*) AS _cnt FROM `".$table."` WHERE ".$where;
        if (SQL_LOG) {
            $this->outLog($sql);
        }
        /** @var  $result \mysqli_result */
        $result = $this->db->query($sql);
        $row = mysqli_fetch_array($result, MYSQLI_ASSOC);
        return intval($row['_cnt']);
    }

    /**
     * 更新, 返回受影响的行
     * @param array $diff
     * @param string $where
     * @return int
     */
    public function update(array $diff, /* string */ $where) {
        $sql = "UPDATE `".$this->table."` SET ";
        $aSet = array();
        foreach ($diff as $name => $value) {
            $aSet[] = sprintf("`%s`='%s'", $name, $value);
        }
        $sql .= implode(",", $aSet);
        $sql .= " WHERE ".$where;
        if (SQL_LOG) {
            $this->outLog($sql);
        }
        /** @var $ret \mysqli_stmt */
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        return $stmt->affected_rows;
    }

    public function insertGetId(/* string */$table, /* array */$assoc) {
        $tpl = "INSERT INTO ".$table."(%s) VALUES(%s)";
        $names = array_keys($assoc);
        $values = array_values($assoc);
        $sql = sprintf($tpl, "`".implode("`,`", $names)."`", "'".implode("','", $values)."'");
        if (SQL_LOG) {
            $this->outLog($sql);
        }
        $this->db->query($sql);
        return $this->db->insert_id;
    }
}